/**
 * 浏览器缩放检测与适配工具
 * 用于在浏览器缩放时应用特殊样式，解决vw单位在缩放时的问题
 */

export class ZoomDetector {
  private static instance: ZoomDetector;
  private zoomLevel: number = 1;
  private readonly defaultZoomClass = 'zoom-level';
  private readonly zoomChangeListeners: Array<(zoomLevel: number) => void> = [];

  /**
   * 获取单例实例
   */
  public static getInstance(): ZoomDetector {
    if (!ZoomDetector.instance) {
      ZoomDetector.instance = new ZoomDetector();
    }
    return ZoomDetector.instance;
  }

  /**
   * 初始化缩放检测
   * @param options 配置选项
   */
  public init(options?: { detectInterval?: number }) {
    // 初始检测
    this.detectZoom();
    
    // 监听缩放事件
    window.addEventListener('resize', this.onResize.bind(this));
    
    // 定期检测缩放级别变化
    const interval = options?.detectInterval || 1000;
    setInterval(() => this.detectZoom(), interval);
    
    // 初始应用样式
    this.applyZoomClass();
  }

  /**
   * 添加缩放变化监听器
   * @param listener 监听器函数
   */
  public addZoomChangeListener(listener: (zoomLevel: number) => void) {
    this.zoomChangeListeners.push(listener);
  }

  /**
   * 移除缩放变化监听器
   * @param listener 要移除的监听器函数
   */
  public removeZoomChangeListener(listener: (zoomLevel: number) => void) {
    const index = this.zoomChangeListeners.indexOf(listener);
    if (index !== -1) {
      this.zoomChangeListeners.splice(index, 1);
    }
  }

  /**
   * 获取当前缩放级别
   */
  public getZoomLevel(): number {
    return this.zoomLevel;
  }

  /**
   * 检测当前浏览器缩放级别
   * @returns 当前缩放级别
   */
  private detectZoom(): number {
    const prevZoom = this.zoomLevel;
    
    // 使用devicePixelRatio和screen.logicalXDPI计算缩放级别
    let zoom = Math.round((window.devicePixelRatio || 1) * 100) / 100;
    
    // 在某些浏览器中，可以使用visualViewport
    if (window.visualViewport) {
      zoom = Math.round((window.visualViewport.scale || 1) * 100) / 100;
    }
    
    this.zoomLevel = zoom;
    
    // 如果缩放级别发生变化，触发监听器
    if (prevZoom !== zoom) {
      this.applyZoomClass();
      this.notifyZoomChange();
    }
    
    return zoom;
  }

  /**
   * 窗口大小改变事件处理
   */
  private onResize() {
    this.detectZoom();
  }

  /**
   * 应用缩放级别相关的CSS类
   */
  private applyZoomClass() {
    const root = document.documentElement;
    
    // 移除之前的缩放类
    const classesToRemove = Array.from(root.classList)
      .filter(cls => cls.startsWith(this.defaultZoomClass));
    
    classesToRemove.forEach(cls => root.classList.remove(cls));
    
    // 添加新的缩放类
    const zoomPercentage = Math.round(this.zoomLevel * 100);
    root.classList.add(`${this.defaultZoomClass}-${zoomPercentage}`);
    
    // 设置CSS变量以便在样式中使用
    root.style.setProperty('--zoom-level', this.zoomLevel.toString());
    root.style.setProperty('--zoom-level-percent', `${zoomPercentage}%`);
    
    // 缩放小于1时，添加缩小类
    if (this.zoomLevel < 1) {
      root.classList.add('zoom-out');
      root.classList.remove('zoom-in');
    } 
    // 缩放大于1时，添加放大类
    else if (this.zoomLevel > 1) {
      root.classList.add('zoom-in');
      root.classList.remove('zoom-out');
    }
    // 恢复默认缩放时，移除缩放类
    else {
      root.classList.remove('zoom-in', 'zoom-out');
    }
  }

  /**
   * 通知所有监听器缩放级别变化
   */
  private notifyZoomChange() {
    this.zoomChangeListeners.forEach(listener => {
      try {
        listener(this.zoomLevel);
      } catch (e) {
        console.error('Error in zoom change listener:', e);
      }
    });
  }
}

/**
 * 全局实例
 */
export const zoomDetector = ZoomDetector.getInstance(); 